package com.ucode.application.controller.search;

import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ucode.search.crm.model.ESBusiness;
import com.ucode.search.crm.model.ESContacts;
import com.ucode.search.crm.model.ESCustomer;
import com.ucode.search.crm.model.ESFollowRecord;
import com.ucode.springboot.starter.ESsearch.annotation.ESDocument;
import com.ucode.springboot.starter.ESsearch.annotation.metadata.ESDocumentData;
import com.ucode.springboot.starter.ESsearch.repository.ElasticsearchDocSourceTemplate;
import com.ucode.springboot.starter.ESsearch.repository.ElasticsearchIndexTemplate;
import com.ucode.springboot.starter.ESsearch.repository.ElasticsearchSearchTemplate;
import com.ucode.springboot.starter.ESsearch.util.EsTools;
import com.ucode.sys.model.User;
import com.ucode.tool.base.ResponseResult;
import com.ucode.tool.util.IdentifyUtils;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@Api(tags="ES全文检索")
@RestController
@RequestMapping("/sys-es")
@Validated
public class ESDemoController {

    private static Log log = LogFactory.get(ESDemoController.class);
    
    @Autowired
    private ElasticsearchIndexTemplate esIndexTemplate;
    
    @Autowired
    private ElasticsearchIndexTemplate<ESCustomer> customerIndexTemplate;
    
    @Autowired
    private ElasticsearchIndexTemplate<ESContacts> contactsIndexTemplate;
    
    @Autowired
    private ElasticsearchIndexTemplate<ESFollowRecord> followRecordIndexTemplate;
    
    @Autowired
    private ElasticsearchIndexTemplate<ESBusiness> businessIndexTemplate;
    
    @Autowired
    private ElasticsearchSearchTemplate<Person, Long> esSearchTemplate;
    
    @Autowired
    private ElasticsearchSearchTemplate<ESCustomer, Long> esSearchTemplate2;
    
    @Autowired
    private ElasticsearchDocSourceTemplate<Person, Long> esDocSourceTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation("原生搜索")
    @GetMapping(value = "/search")
    public ResponseResult<Object> search(
            @ApiParam(value ="关键字")  @RequestParam(value = "ss") String fieldValue){
        
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(Person.class);
        String indexname = metaData.getIndexname();
        
        SearchRequest searchRequest = new SearchRequest(new String[]{indexname});
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        
        searchSourceBuilder.query(new MatchAllQueryBuilder());//匹配所有
        searchSourceBuilder.from(0);//从第0条开始
        searchSourceBuilder.size(10);//返回10条
        searchRequest.source(searchSourceBuilder);
        
        List<ESCustomer> list = new ArrayList<ESCustomer>();
        try {
            SearchResponse searchResponse = esSearchTemplate2.search(searchRequest);
            
            SearchHits hits = searchResponse.getHits();
            SearchHit[] searchHits = hits.getHits();
            
            for (SearchHit hit : searchHits) {
                list.add(objectMapper.readValue(hit.getSourceAsString(),ESCustomer.class));
            }
        } catch (Exception e) {
            log.error(e);
        }
        
        return ResponseResult.success(list);
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation("不分页条件查询")
    @GetMapping(value = "/search1")
    public ResponseResult<Object> search1( @ApiParam(value ="关键字")  @RequestParam(value = "keyword") String keyword){
        
        List<Person> result = null;
        
        try {
            /**
             *  must(QueryBuilders) :   AND
             * mustNot(QueryBuilders): NOT
             * should:                  : OR
             */
            QueryBuilder queryBuilder = 
//                    QueryBuilders.nestedQuery("details", QueryBuilders.boolQuery()
//                    .must(QueryBuilders.matchQuery("details.address", keyword)), ScoreMode.Avg);
            QueryBuilders.boolQuery()
            .should(QueryBuilders.multiMatchQuery(keyword, "name","country","remark"))
            .should(QueryBuilders.nestedQuery("details", QueryBuilders.boolQuery()
                    .must(QueryBuilders.matchQuery("details.address", keyword)), ScoreMode.Avg));
            
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            for (int i = 0; i < 40; i++) {
                String k = "";
                for (int j = 0; j < 50; j++) {
                    k = k+IdentifyUtils.getDefaultSnowflakeId()+" ";
                }
                boolQueryBuilder = boolQueryBuilder.should(QueryBuilders.multiMatchQuery(k, "name","country","remark"));
            }
            boolQueryBuilder = boolQueryBuilder.should(QueryBuilders.multiMatchQuery(keyword, "name","country","remark"));
//            QueryBuilders.boolQuery().must(QueryBuilders.termsQuery(name, values));
//            
//            QueryBuilders.boolQuery().must(queryBuilder).must(queryBuilder)
            
            result =  esSearchTemplate.search(boolQueryBuilder, Person.class);
        } catch (Exception e) {
            log.error(e);
        }
        
        return ResponseResult.success(result);
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation("客户权限查询案例")
    @GetMapping(value = "/search3")
    public ResponseResult<Object> search3( @ApiParam(value ="关键字")  @RequestParam(value = "keyword") String keyword){
        
        List<ESCustomer> result = null;
        
        try {
            QueryBuilder queryBuilder = QueryBuilders.matchQuery("ownerUserIdStr",keyword);
                    
//                    QueryBuilders.multiMatchQuery(keyword, "ownerUserIdStr","teamUserIds");
            
            result =  esSearchTemplate2.search(queryBuilder, ESCustomer.class);
        } catch (Exception e) {
            log.error(e);
        }
        
        return ResponseResult.success(result);
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation("搜索建议")
    @GetMapping(value = "/searchSuggest")
    public ResponseResult<Object> searchSuggest(
            @ApiParam(value ="关键字")  @RequestParam(value = "ss") String fieldValue){
        
        List<String> result = null;
        try {
            result =  esSearchTemplate.searchSuggest("name", fieldValue, Person.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return ResponseResult.success(result);
    }
    
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation("关键字检索")
    @GetMapping(value = "/search2")
    public ResponseResult<Object> search2(
            @ApiParam(value ="日期")  @RequestParam(value = "keyword") String  keyword){
        
        QueryBuilder queryBuilder = QueryBuilders.matchQuery("name",keyword);
        List<Person> list = null;
        try {
            list = esSearchTemplate.search(queryBuilder, Person.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return ResponseResult.success(list);
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation("根据主键查询索引文档")
    @GetMapping(value = "/getById/{id}")
    public ResponseResult<Object> getById(@PathVariable(name="id",required=true) Long id){
        Person person;
        try {
            person = esSearchTemplate.getById(id, Person.class);
            return ResponseResult.success(person);
        } catch (Exception e) {
        }
        return ResponseResult.failed();
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation(value="创建索引结构")
    @PostMapping("/createIndex")
    public ResponseResult<Object> createIndex() {
        
        boolean result = true;
        try {
//            esIndexTemplate.createIndex(ESCustomer.class);
//            esIndexTemplate.createIndex(ESContacts.class);
//            followRecordIndexTemplate.createIndex(ESFollowRecord.class);
            businessIndexTemplate.createIndex(ESBusiness.class);
        } catch (Exception e) {
            log.error(e);
            result = false;
        }
        return result ? ResponseResult.success() : ResponseResult.failed();
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation(value="删除索引结构")
    @PostMapping("/dropIndex")
    public ResponseResult<Object> dropIndex() {
        
        boolean result = true;
        try {
            esIndexTemplate.dropIndex(ESCustomer.class);
        } catch (Exception e) {
            log.error(e);
            result = false;
        }
        return result ? ResponseResult.success() : ResponseResult.failed();
    }
    
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation(value="保存索引文档")
    @PostMapping("/saveDoc")
    public ResponseResult<Object> saveDoc(@Validated @RequestBody Person person) {
        boolean result = false;
        try {
            result = esDocSourceTemplate.save(person);
        } catch (Exception e) {
            log.error(e);
            
        }
        return result ? ResponseResult.success() : ResponseResult.failed();
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation(value="更新索引文档")
    @PostMapping("/updateDoc")
    public ResponseResult<Object> updateDoc(@Validated @RequestBody Person person) {
        boolean result = false;
        try {
            result = esDocSourceTemplate.update(person);
        } catch (Exception e) {
            log.error(e);
            
        }
        return result ? ResponseResult.success() : ResponseResult.failed();
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation(value="删除索引文档")
    @PostMapping("/deleteDoc/{id}")
    public ResponseResult<Object> deleteDoc(@PathVariable(name="id",required=true) Long id) {
        boolean result = false;
        try {
            result = esDocSourceTemplate.deleteById(id, Person.class);
        } catch (Exception e) {
            log.error(e);
            
        }
        return result ? ResponseResult.success() : ResponseResult.failed();
    }
    
}
